//
// Maths.cpp for  in /home/goldbe_y//cpp/Maths/207correl
//
// Made by yoni goldberg
// Login   <goldbe_y@epitech.net>
//
// Started on  Mon May 16 19:41:01 2011 yoni goldberg
// Last update Sat May 28 18:48:01 2011 leo faucon
//

#include "Maths.hpp"

#include "convert.hpp"
#include "SDL_graph.hpp"

double		Moy(std::vector<float> tab)
{
  double	res = 0;
  for (int i = 0; i < (int)tab.size(); i++)
    res += tab[i];
  res /= tab.size();
  return res;
}

Maths::Maths(std::vector<float> _x, std::vector<float> _y, int _line, int opt)
{

  X = _x;
  Y = _y;

  borne_x_b = 0;

  size_t	i = 0;
  while (i < X.size())
    {
      if (X[i] > borne_x_b)
	borne_x_b = X[i];
      i++;
    }

  borne_x_a = borne_x_b;

  i = 0;
  while (i < X.size())
    {
      if (X[i] < borne_x_a)
  	borne_x_a = X[i];
      i++;
    }


  borne_y_b = 0;

  i = 0;
  while (i < Y.size())
    {
      if (Y[i] > borne_y_b)
	borne_y_b = Y[i];
      i++;
    }

  borne_y_a = borne_y_b;

  i = 0;
  while (i < Y.size())
    {
      if (Y[i] < borne_y_a)
  	borne_y_a = Y[i];
      i++;
    }

  if (opt == 1)
    {
      X = _y;
      Y = _x;
    }

  line = _line;
  calcA();
  calcB();
  calcS();
  calcR();


}

double		Maths::calc(double x, double ca, double cb)
{
  return (ca + (cb * x));
}

double		Maths::ecart(int i)
{
  double	res;

  res = Y[i];
  return (res - calc(X[i], a, b));
}

double		Maths::somme(int mode)
{
  double	res = 0;

  double m = Moy(Y);
  switch (mode)
    {
    case 0:
      for (int i = 0; i < line; i++)
	res += X[i];
      break;
    case 1:
      for (int i = 0; i < line; i++)
	res += Y[i];
      break;
    case 2:
      for (int i = 0; i < line; i++)
	res += pow(X[i],2);
      break;
    case 3:
      for (int i = 0; i < line; i++)
	res += (X[i] * Y[i]);
      break;
    case 4:
      for (int i = 0; i < line; i++)
	res += pow(ecart(i), 2);
      break;
    case 5:
      for (int i = 0; i < line; i++)
	res += pow(calc(X[i], a, b) - m, 2);
      break;
    case 6:
      for (int i = 0; i < line; i++)
	res += pow(Y[i] - m,2);
    }
  return res;
}

void		Maths::calcA()
{
  double		temp;
  a = somme(1);
  a *= somme(2);
  temp = somme(0);
  temp *= somme(3);
  a -= temp;
  temp = X.size();
  temp *= somme(2);
  temp -= pow(somme(0), 2);
  a /= temp;
}

void		Maths::calcB()
{
  double		temp;
  b = X.size();
  b *= somme(3);
  temp = somme(0);
  temp *= somme(1);
  b -= temp;
  temp = X.size();
  temp *= somme(2);
  temp -= pow(somme(0), 2);
  b /= temp;
}

void		Maths::calcS()
{
  double	temp;
  temp = somme(4);
  temp /= X.size();
  s = sqrt(temp);
}

void		Maths::calcR()
{
  double	temp;
  temp = somme(5);
  temp /= somme(6);
  r = sqrt(temp);
}

double		calc_aff(double y)
{
  double hauteur = y;
  double tmp = 550 - hauteur;
  return (tmp);
}


void	Maths::axes_courbe(SDL_opt * win, SDL_graph * graph)
{
  int	i;
  int	grad = 50;

  win->position.x = 45;
  win->position.y = 560;
  x_grad = 500 / ((borne_x_b - borne_x_a) + 1);
  (borne_x_a > 0) ? (i = borne_x_a - 1) : (i = borne_x_a);
  while (i < (borne_x_b + 1))
    {
      if (i == 0 || i == borne_x_a - 1)
	graph->ligne_graphVerticale(grad,20,530, graph->couleurs[12]);
      else
	graph->ligne_graphVerticale(grad,540,10, graph->couleurs[12]);
      std::string str = var_to_string(i, 0);
      win->aff_texte(str, win->couleurJaune);
      if ((borne_x_b - borne_y_a) > 15)
	{
	  i += 4;
	  grad += (x_grad * 4);
	  win->position.x += (x_grad * 4);
	}
      else
	{
	  grad += x_grad;
	  win->position.x += x_grad;
	  i++;
	}
    }

  grad = 540;
  win->position.x = 10;
  win->position.y = 550;
  y_grad = 500 / (borne_y_b - borne_y_a);
  (borne_y_a > 0) ? (i = borne_y_a - 1) : (i = borne_y_a);
  while (i < (borne_y_b + 1))
    {
      if (i == 0 || i == borne_y_a - 1)
	graph->ligne_graphHorizontale(50, 550, 500, graph->couleurs[12]);
      else
	{
	  graph->ligne_graphHorizontale(40,win->position.y,10, graph->couleurs[12]);
	  std::string str = var_to_string(i, 0);
	  win->aff_texte(str, win->couleurJaune);
	}
      if ((borne_y_b - borne_y_a)> 15)
	{
	  i += 4;
	  grad += (y_grad * 4);
	  win->position.y -= (y_grad * 4);
	}
      else
	{
	  grad += y_grad;
	  win->position.y -= y_grad;
	  i++;
	}
    }

}

void		Maths::courbe(SDL_opt * win, double ca1, double cb1, double ca2, double cb2)
{
  SDL_graph	graph(win->get_ecran());
  axes_courbe(win, &graph);

  // 1ere droite
  double	x = x_grad * 2;
  double	y = calc_aff((calc(borne_x_a, ca1, cb1) - (borne_y_a - 1)) * y_grad);
  double	save_x = x;
  double	save_y = y;

  x = ((borne_x_b - (borne_x_a - 1)) * x_grad) + x_grad;
  y = calc_aff((calc(borne_x_b, ca1, cb1) - (borne_y_a - 1)) * y_grad);

  graph.ligne_graph(save_x, save_y, x, y, graph.couleurs[11]);

  // 2eme droite

  x = ((calc(borne_y_a + 1, ca2, cb2) - (borne_x_a - 1)) * x_grad) + x_grad;
  y = calc_aff(y_grad * 2);
  save_x = x;
  save_y = y;
  x = ((calc(borne_y_b, ca2, cb2) - (borne_x_a - 1)) * x_grad) + x_grad;
  y = calc_aff((borne_y_b - (borne_y_a - 1)) * y_grad);
  graph.ligne_graph(save_x, save_y, x, y, graph.couleurs[9]);

  // Les points

  for (size_t i = 0; i < X.size(); i++)
    {
      x = ((Y[i] - (borne_x_a - 1)) * x_grad) + x_grad;
      y = calc_aff((X[i] - (borne_y_a -1)) * y_grad);
      graph.ligne_graph(x-3, y, x+3, y, graph.couleurs[2]);
      graph.ligne_graph(x, y-3, x, y+3, graph.couleurs[2]);
    }

  // affichage
  graph.actualiser();
  while (1)
    {
      int ret = graph.attendreTouche();
      if (ret == -1 || ret == SDLK_ESCAPE)
	break;
    }
}
